package org.br.plotter.functions;

import java.util.*;

public class MultiFunction extends Function {
	public MultiFunction() {
	}

	private Function left;
	private Function right;
	private int index;
	final private static char[] operators = { '^', '/', '*', '&', '|', '-', '+' };

	public void setLeft(Function left) {
		this.left = left;
	}

	public void setRight(Function right) {
		this.right = right;
	}

	public static Function toFunction(List<Function> functions,
			List<Integer> ops) {
		return toFunction(functions.iterator(), ops.iterator());
	}

	private static Function toFunction(Iterator<Function> functions,
			Iterator<Integer> ops) {
		if (!ops.hasNext())
			return functions.next();
		MultiFunction mf = new MultiFunction();
		mf.setLeft(functions.next());
		mf.index = ops.next();
		mf.right = functions.next();
		MultiFunction branch = mf;
		int op = -1;
		while (ops.hasNext()) {
			op = ops.next();
			Function t = functions.next();
			branch = adjustFunction(branch, op, t);

		}

		return mf;
	}

	private static MultiFunction adjustFunction(MultiFunction branch, int op,
			Function tmp) {
		System.out.println("Eval Function:" + tmp.eval(1));
		System.out.println("Operation:" + op);
		int opPrevios = branch.index;
		if (op < opPrevios) {
			return adjustRight(branch, op, tmp);
		} else {
			return adjustLeft(branch, op, tmp);
		}

	}

	private static MultiFunction adjustRight(MultiFunction mf, int op,
			Function tmp) {
		MultiFunction right = new MultiFunction();
		right.right = tmp;
		right.index = op;
		right.left = mf.right;
		mf.right = right;
		return mf;
	}

	private static MultiFunction adjustLeft(MultiFunction mf, int op,
			Function tmp) {
		MultiFunction left = new MultiFunction();
		left.left = mf.left;
		left.right = mf.right;
		left.index = mf.index;
		mf.left = left;
		mf.right = tmp;
		mf.index = op;
		return mf;
	}

	public void setOperation(int index) {
		this.index = index;
	}

	public double eval(double x) {
		double rightDouble = right.eval(x);
		System.out.println("******Right=" + rightDouble);
		double leftDouble = left.eval(x);
		System.out.println("******Left=" + leftDouble);
		System.out.println("******OP=" + index);
		switch (index) {
		case 0:
			return Math.pow(leftDouble, rightDouble);
		case 1:
			return leftDouble / rightDouble;
		case 2:
			return leftDouble * rightDouble;
		case 3:
			return Double.longBitsToDouble(Double
					.doubleToRawLongBits(leftDouble)
					& Double.doubleToRawLongBits(rightDouble));
		case 4:
			return Double.longBitsToDouble(Double
					.doubleToRawLongBits(leftDouble)
					| Double.doubleToRawLongBits(rightDouble));
		case 5:
			return leftDouble - rightDouble;
		case 6:
			return leftDouble + rightDouble;
		default:
			throw new RuntimeException("Unsupported Operation:" + index);
		}
	}

	public static void main(String[] args) {
		Function contant3 = new ConstFunction(2);
		Function contant4 = new ConstFunction(4);
		Function contant5 = new ConstFunction(3);
		Function contant6 = new ConstFunction(6);
		List<Integer> ops = new LinkedList<Integer>();

		ops.add(0);
		ops.add(2);
		ops.add(6);
		List<Function> f = new LinkedList<Function>();
		f.add(contant4);
		f.add(contant6);
		f.add(contant5);
		f.add(contant3);
		Function fun = toFunction(f, ops);
		System.out.println(fun.eval(4));

	}
}